﻿using AutoMapper;
using BingYing.SAAS.SystemModel.Application.BaseInfo;
using BingYing.SAAS.SystemModel.Application.Events;
using BingYing.SAAS.SystemModel.Application.Model;
using BingYing.SAAS.SystemModel.Contracts.Manager;
using BingYing.SAAS.SystemModel.Domain.Manager;
using Microsoft.AspNetCore.Authorization;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.DependencyInjection;
using Qianke.Core.Common;
using Qianke.Core.Common.NameMutex;
using Volo.Abp.Auditing;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.EventBus.Local;
using Volo.Abp.ObjectMapping;

namespace BingYing.SAAS.SystemModel.Application.Manager
{
    /// <summary>
    /// 管理者服务
    /// </summary>
    [Authorize("MastLogin")]
    public class ManagerService : SaasBaseService<ManagerInfo, long, GetModelOutputDto, AddOrUpdateInputDto, GetPageInputDto, GetPageOutputDto>
        , IManagerService
    {
        /// <summary>
        /// 管理者服务构造函数
        /// </summary>
        /// <param name="repository"></param>
        /// <param name="objectMapper"></param>
        public ManagerService(IRepository<ManagerInfo, long> repository, IMapper objectMapper)
            : base(repository, objectMapper)
        {
        }

        public async Task Add()
        {
            await repository.InsertAsync(new ManagerInfo()
            {
                UserName = "admin",
                Password = "admin123",
                Email = "admin@123.com",
            });
        }


        /// <summary>
        /// 登录系统
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        [AllowAnonymous]
        [DisableAuditing]
        public async Task<LoginOutputDto> LoginUser(LoginInputDto dto)
        {
            var model = await repository.FirstOrDefaultAsync(u => u.UserName == dto.UserName && u.Password == dto.Password);
            if (model == null)
                throw new Exception("用户名或密码错误");

            var cache = LazyServiceProvider.GetService<IDistributedCache>();

            var keyName = $"{dto.UserName}{dto.Password}";
            var result = await cache.GetStringAsync(keyName);
            if (result != null)
                return result.ToObject<LoginOutputDto>();


            var nameMutexManager = LazyServiceProvider.GetRequiredService<INameMutexManager>();
            await using (var mutex = await nameMutexManager.CreateMutex(model.UserName))
            {
                await mutex.EnterAsync();
                var (token, expiresTime) = CreateToken(model);
                model.LastLoginTime = DateTime.Now;
                await repository.UpdateAsync(model);

                await LazyServiceProvider
                    .GetRequiredService<ILocalEventBus>()
                    .PublishAsync(new LoginEventArg() { Manager = model });
                var resultDto =  new LoginOutputDto()
                {
                    Email = model.Email,
                    Id = model.Id,
                    UserName = model.UserName,
                    Token = token,
                    ExpirationTime = expiresTime,
                };
                await cache.SetStringAsync(keyName, resultDto.ToJson());
                return resultDto;
            }
        }

        /// <summary>
        /// 创建令牌
        /// </summary>
        /// <param name="managerInfo"></param>
        /// <returns></returns>
        private (string Token, DateTime ExpiresTime) CreateToken(ManagerInfo managerInfo)
        {
            var expiresTime = DateTime.Now.AddHours(24);
            var token = TokenHelper.CreateToken(new TokenInfo()
            {
                Id = managerInfo.Id,
                LastTime = expiresTime,
                Name = managerInfo.UserName,
                OrganId = managerInfo.OrganId
            });
            return (token, expiresTime);
        }
    }
}
